/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bemanager.generatecomponent;

import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.BaseComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.BeComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.BeMgrComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.DeterminationComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.TccActionComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.ValidationComponentGenerator;
import com.inspur.edp.bef.bemanager.util.DataValidatorUtil;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.common.BizEntityJsonConst;
import com.inspur.edp.bef.bizentity.common.OperationConvertUtils;
import com.inspur.edp.bef.bizentity.operation.collection.DeterminationCollection;
import com.inspur.edp.bef.bizentity.operation.collection.ValidationCollection;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.TccSettingElement;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.collection.CommonValCollection;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.operation.CommonDetermination;
import com.inspur.edp.cef.designtime.api.operation.CommonValidation;
import com.inspur.edp.cef.variable.dtgenerator.vardtmGenerate.cmpgenerators.CommonDtmGenerator;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.sun.xml.internal.ws.developer.MemberSubmissionAddressing.Validation;
import java.util.ArrayList;
import lombok.Getter;
import lombok.var;

public class ComponentGenerator {


  public static ComponentGenerator getInstance() {
    return new ComponentGenerator();
  }

  private ComponentGenerator() {
    this.createComponentActionList = new ArrayList<>();
  }

  @Getter
  private boolean anyGenerated;
  /**
   * 用来记录已生成构件的编号
   */
  private final ArrayList<String> createComponentActionList;
  /**
   * BE的编号
   */
  private String privateBizEntityCode;

  private String getBizEntityCode() {
    return privateBizEntityCode;
  }

  private void setBizEntityCode(String value) {
    privateBizEntityCode = value;
  }

  /**
   * BE的程序集名称
   */
  private String privateAssemblyName;

  private String getAssemblyName() {
    return privateAssemblyName;
  }

  private void setAssemblyName(String value) {
    privateAssemblyName = value;
  }

  private String privateNameSpace;

  private String getNameSpace() {
    return privateNameSpace;
  }

  private void setNameSpace(String value) {
    privateNameSpace = value;
  }

  /**
   * 是否子节点
   */
  private boolean privateIsChildObj;

  private boolean getIsChildObj() {
    return privateIsChildObj;
  }

  private void setIsChildObj(boolean value) {
    privateIsChildObj = value;
  }

  /**
   * 当前节点编号
   */
  private String privateObjCode;

  private String getObjCode() {
    return privateObjCode;
  }

  private void setObjCode(String value) {
    privateObjCode = value;
  }

  /**
   * 业务对象ID
   */
  private String privateBizObjectID;

  private String getBizObjectID() {
    return privateBizObjectID;
  }

  private void setBizObjectID(String value) {
    privateBizObjectID = value;
  }

  /**
   * BE变量实体的编号
   */
  private String privateBEVariableEntityCode;

  private String getBEVariableEntityCode() {
    return privateBEVariableEntityCode;
  }

  private void setBEVariableEntityCode(String value) {
    privateBEVariableEntityCode = value;
  }

  private GspMetadata metadata;

  /**
   * 入口：支持Be设计器生成构件元数据
   *
   * @param metadata BE实体
   * @param bePath   be路径
   */
  public ArrayList<String> generateComponent(GspMetadata metadata, String bePath) {
    GspBusinessEntity bizEntity =
        (metadata.getContent() instanceof GspBusinessEntity) ? metadata.getContent() : null;
    String bizObjectID = metadata.getHeader().getBizobjectID();
    // 参数校验
    DataValidatorUtil.CheckForNullReference(bizEntity, "bizEntity");
    DataValidatorUtil.CheckForEmptyString(bePath, "path");
    setAssemblyName(ComponentGenUtil.getComponentAssemblyName(bePath));
    setNameSpace(ComponentGenUtil.getComponentProjInfo(bePath).getNameSpace());
    DataValidatorUtil.CheckForEmptyString(getAssemblyName(), "AssemblyName");
    setBizEntityCode(bizEntity.getCode());
    DataValidatorUtil.CheckForEmptyString(getBizEntityCode(), "BizEntityCode");
    setBizObjectID(bizObjectID);
    this.metadata = metadata;
    String path = ComponentGenUtil.PrepareComponentDir(bePath);
    generateBEMgrComponents(bizEntity, path);
    // 获取根节点
    GspBizEntityObject mainObj = bizEntity.getMainObject();
    generateMainObjComponent(mainObj, path, metadata);
    for (IGspCommonObject childObj : mainObj.getContainChildObjects()) {
      generateChildObjComponent((GspBizEntityObject) childObj, path, metadata);
    }
    generateVariableDtmComponents(bizEntity, path);
    return this.createComponentActionList;
  }

  /**
   * 变量联动计算
   *
   * @param viewModel
   * @param
   */
  private void generateVariableDtmComponents(GspBusinessEntity viewModel, String path) {
    if (viewModel.getVariables() == null) {
      return;
    }

    var cdtDef = viewModel.getVariables();
    setBEVariableEntityCode(viewModel.getVariables().getCode());
    for (CommonDetermination dtmInfo : cdtDef.getDtmBeforeSave()) {
      if (dtmInfo.getIsRef() || !dtmInfo.getIsGenerateComponent()) {
        continue;
      }
      setNewCompActionCode(CommonDtmGenerator.getInstance()
          .GenerateComponent(viewModel, dtmInfo, path, this.getBEVariableEntityCode(),
              this.getAssemblyName(), getNameSpace(), this.getBizObjectID()));
    }
    for (CommonDetermination dtmInfo : cdtDef.getDtmAfterCreate()) {
      if (dtmInfo.getIsRef() || !dtmInfo.getIsGenerateComponent()) {
        continue;
      }
      setNewCompActionCode(CommonDtmGenerator.getInstance()
          .GenerateComponent(viewModel, dtmInfo, path, this.getBEVariableEntityCode(),
              this.getAssemblyName(), getNameSpace(), this.getBizObjectID()));
    }
    for (CommonDetermination dtmInfo : cdtDef.getDtmAfterModify()) {
      if (dtmInfo.getIsRef() || !dtmInfo.getIsGenerateComponent()) {
        continue;
      }
      setNewCompActionCode(CommonDtmGenerator.getInstance()
          .GenerateComponent(viewModel, dtmInfo, path, this.getBEVariableEntityCode(),
              this.getAssemblyName(), getNameSpace(), this.getBizObjectID()));
    }
  }

  /**
   * &#x751f;&#x6210;BEMgr&#x6784;&#x4ef6;
   *
   * @param bizEntity BE&#x5b9e;&#x4f53;
   * @param path      &#x751f;&#x6210;&#x8def;&#x5f84;
   * @param
   */
  private void generateBEMgrComponents(GspBusinessEntity bizEntity, String path) {
    setIsChildObj(false);
    for (BizOperation bizMgrAction : bizEntity.getCustomMgrActions()) {
      if (bizMgrAction.getIsRef() || !bizMgrAction.getIsGenerateComponent()) {
        continue;
      }
      setNewCompActionCode(BeMgrComponentGenerator.getInstance()
          .generateComponent(bizMgrAction, path, this.getBizEntityCode(), this.getAssemblyName(),
              this.getIsChildObj(), bizEntity.getCode(), this.getBizObjectID(), metadata,
              getNameSpace()));
    }
  }

  /**
   * 生成BE主对象中动作对应的构件
   *
   * @param mainObj
   * @param path
   */
  private void generateMainObjComponent(GspBizEntityObject mainObj, String path,
      GspMetadata metadata) {
    setIsChildObj(false);
    generateObjectComponent(mainObj, path, metadata);
  }

  private void generateObjectComponent(GspBizEntityObject obj, String path, GspMetadata metadata) {
    generateBEComponents(obj, path);
    generateDeterminationComponents(obj, path);
    generateValidationComponents(obj, path);
    generateTccActionComponents(obj, path, metadata);
  }

  /**
   * 生成BE子对象中动作对应的构件
   *
   * @param childObj
   * @param path
   */
  private void generateChildObjComponent(GspBizEntityObject childObj, String path,
      GspMetadata metadata) {
    setIsChildObj(true);
    this.setObjCode(childObj.getCode());
    generateObjectComponent(childObj, path, metadata);
    //递归当前子对象的子对象
    if (childObj.getContainChildObjects().size() > 0) {
      for (IGspCommonObject obj : childObj.getContainChildObjects()) {
        generateChildObjComponent((GspBizEntityObject) obj, path, metadata);
      }
    }
  }

  private void generateBEComponents(GspBizEntityObject obj, String path) {
    for (BizOperation bizAction : obj.getCustomBEActions()) {
      if (bizAction.getIsRef() || !bizAction.getIsGenerateComponent()) {
        continue;
      }
      String code = null;
      if (obj.getIsRootNode()) {
        code = obj.getCode();
      } else {
        code = this.getObjCode();
      }
      setNewCompActionCode(BeComponentGenerator.getInstance().generateComponent(bizAction,
          path, this.getBizEntityCode(), this.getAssemblyName(), this.getIsChildObj(), code,
          this.getBizObjectID(), metadata, getNameSpace()));
    }
  }

  private void generateDeterminationComponents(GspBizEntityObject obj, String path) {
    DeterminationCollection determinations = obj.getDeterminations();
    for (BizOperation determination : determinations) {
      if (determination.getIsRef() || !determination.getIsGenerateComponent()) {
        continue;
      }
      String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
      setNewCompActionCode(DeterminationComponentGenerator.getInstance()
          .generateComponent(determination, path, this.getBizEntityCode(), this.getAssemblyName(),
              this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
    }
    generateCommonDtm(obj, path, obj.getDtmAfterCreate(), CefNames.DtmAfterCreate);
    generateCommonDtm(obj, path, obj.getAllDtmAfterModify(), CefNames.DtmAfterModify);
    generateCommonDtm(obj, path, obj.getAllDtmBeforeSave(), CefNames.DtmBeforeSave);
    generateCommonDtm(obj, path, obj.getDtmBeforeQuery(), BizEntityJsonConst.B4QueryDtm);
    generateCommonDtm(obj, path, obj.getDtmAfterQuery(), BizEntityJsonConst.AftQueryDtm);
    generateCommonDtm(obj, path, obj.getDtmCancel(), BizEntityJsonConst.DtmCancel);
    generateCommonDtm(obj, path, obj.getDtmBeforeRetrieve(), BizEntityJsonConst.B4RetrieveDtm);
    generateCommonDtm(obj, path, obj.getDtmAfterLoading(), BizEntityJsonConst.AftLoadingDtm);
  }

  private void generateCommonDtm(GspBizEntityObject obj, String path,
      CommonDtmCollection dtmCollection, String commonDtmType) {
    if (dtmCollection == null) {
      return;
    }
    for (CommonDetermination dtm : dtmCollection) {
      if (dtm.getIsRef() || !dtm.getIsGenerateComponent()
          || obj.getDeterminations().findById(dtm.getID()) != null) {
        continue;
      }
      Determination determination = OperationConvertUtils.convertToDtm(dtm, commonDtmType, obj);
      String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
      setNewCompActionCode(DeterminationComponentGenerator.getInstance().generateComponent(
          determination, path, this.getBizEntityCode(), this.getAssemblyName(),
          this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
      dtm.setComponentId(determination.getComponentId());
      dtm.setComponentName(determination.getComponentName());
      dtm.setComponentPkgName(determination.getComponentPkgName());
    }
  }

  private void generateValidationComponents(GspBizEntityObject obj, String path) {
    ValidationCollection validations = obj.getValidations();
    for (BizOperation validation : validations) {
      if (validation.getIsRef() || !validation.getIsGenerateComponent()) {
        continue;
      }
      String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
      setNewCompActionCode(ValidationComponentGenerator.getInstance()
          .generateComponent(validation, path, this.getBizEntityCode(), this.getAssemblyName(),
              this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
    }
    generateCommonVal(obj, path, obj.getValAfterSave(), BizEntityJsonConst.ValidationAfterSave);
    generateCommonVal(obj, path, obj.getallValBeforeSave(), CefNames.ValBeforeSave);
    generateCommonVal(obj, path, obj.getAllValAfterModify(), CefNames.ValAfterModify);
  }

  private void generateCommonVal(GspBizEntityObject obj, String path,
      CommonValCollection collection, String commonType) {
    if (collection == null) {
      return;
    }
    for (CommonValidation item : collection) {
      if (item.getIsRef() || !item.getIsGenerateComponent()
          || obj.getValidations().findById(item.getID()) != null) {
        continue;
      }
      Validation validation = OperationConvertUtils.convertToVal(item, commonType, obj);
      String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
      setNewCompActionCode(ValidationComponentGenerator.getInstance().generateComponent(
          validation, path, this.getBizEntityCode(), this.getAssemblyName(),
          this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
      item.setComponentId(validation.getComponentId());
      item.setComponentName(validation.getComponentName());
      item.setComponentPkgName(validation.getComponentPkgName());
    }
  }

  private void generateTccActionComponents(GspBizEntityObject obj, String path,
      GspMetadata metadata) {

    for (TccSettingElement ele : obj.getTccSettings()) {
      TccAction action = ele.getTccAction();
      if (action.getIsRef() || !action.getIsGenerateComponent()) {
        continue;
      }
      String code = null;
      if (obj.getIsRootNode()) {
        code = obj.getCode();
      } else {
        code = this.getObjCode();
      }
      setNewCompActionCode(
          TccActionComponentGenerator.getInstance().generateComponent(ele, path, metadata, code));
    }
  }

  private void setNewCompActionCode(String code) {
    anyGenerated = true;
    if (code == null || code.equals("")) {
      return;
    }
    this.createComponentActionList.add(code);
  }

  public GspMetadata createCompByOperation(BizOperation operation, String bePath,
      String bizEntityCode, boolean isChildObj, String objCode, String bizObjectID) {
    String path = ComponentGenUtil.PrepareComponentDir(bePath);
    String assemblyName = ComponentGenUtil.getComponentAssemblyName(bePath);
    String defaultNameSpace = ComponentGenUtil.getComponentProjInfo(bePath).getNameSpace();
    BaseComponentGenerator generator = ComponentGeneratorFactory.getInstance().getGenerator(
        operation.getOpType());
    return generator.createComponent(operation, path, bizEntityCode, assemblyName, isChildObj,
        objCode, bizObjectID, defaultNameSpace);
  }

  public GspMetadata createCompByVarDtm(CommonDetermination dtm, GspBusinessEntity be, String path,
      String bizObjectId) {
    String assemblyName = ComponentGenUtil.getComponentAssemblyName(path);
    String nameSpace = ComponentGenUtil.getComponentProjInfo(path).getNameSpace();

    return CommonDtmGenerator.getInstance()
        .createComponent(be, dtm, path, be.getVariables().getCode(),
            assemblyName, nameSpace, bizObjectId);
  }
}
